package main

import (
	"fmt"
	"time"
)

// 定时器  和 断续器
/**

	定时器：延时某些操作任务
	断续器：设置的好间隔时间，周而复始的执行任务

	有两种方式创建定时器：
		time.NewTimer 函数 和 time.AfterFunc 函数
		这两个函数将得到 time.Timer 类型

		// timer.Reset(time.Second * 3) 重置定时器，并设置定时器间隔时间
		// timer.Stop() 停止定时器
		// time.Sleep(time.Second) // 睡眠，一秒

		timer.Reset(...) 和 timer.Sleep() 返回值是一个 bool 值。
		如果值为 false 表示，这个定时器已经过期(或者结束了)，
		如果值为 true 表示，已经成功 重置 或者 停止


		time.NewTimer 函数 和 time.AfterFunc 函数 创建的定时器只能执行一次，
		需要配合 for 和 select 才能周而复始的执行


	断续器：
		time.NewTicker 函数创建, 可以周而复始的执行，比如每次间隔3秒执行一次任务

**/

// ========================  定时器

// 定时器例子 time.NewTimer 方式
func timer1() {

	// 这里的定时器，执行完就会结束(因为main函数结束了)，如果想周而复始的执行，使用 for 和 select 方式

	// 创建一个到期时间的间隔为 3 秒的定时器
	// 参数 time.Duration 类型
	timer := time.NewTimer(time.Second * 3)
	fmt.Printf("定时器开始时间：%v\n", time.Now().Format("2006-01-02 15:04:05"))
	// <-timer.C 表示接收这个管道的值, 传递过来的是它到期的时间

	// 间隔一段时间执行下面的代码, 管道有值表示定时器的执行任务的时间到了
	expTime := <-timer.C
	fmt.Printf("定时器结束时间：%v\n", time.Now().Format("2006-01-02 15:04:05"))
	// 指定自定义的时间进行格式化
	// time.Parse("2006-01-02 15:04:05", "2020-10-01 10:10:01")
	fmt.Printf("接收定时器管道的值：%v", expTime.Format("2006-01-02 15:04:05"))
	fmt.Printf("停止定时器：%v", timer.Stop())

	// timer.Reset(time.Second * 3) 重置定时器，并设置定时器间隔时间
	// timer.Stop() 停止定时器
	// time.Sleep(time.Second) // 睡眠，一秒
}

// 定时器例子 time.AfterFunc 方式
func timer2() {
	// 这里的定时器，执行完就会结束(因为main函数结束了)，如果想周而复始的执行，使用 select 方式

	// 创建一个到期时间的间隔为 3 秒的定时器
	time.AfterFunc(time.Second*3, func() {
		// 我需要执行操作...
		fmt.Printf("定时器执行中！")
	})

	// time.AfterFunc 函数不会往 C <- timer.C 管道中发送数据，而是启用 goroutine 去执行传递进去的函数
}

// 定时器例子
// 上面的例子，会发现只执行了一次，
// 这个例子适用于指定我们需要执行的次数
// 这里使用 time.NewTimer 做例子
func timer3() {

	t := time.Second * 3
	var timer *time.Timer

	// 执行任务的通信管道
	intChan := make(chan int, 1)
	go func() {
		// 设置需要执行次数
		// 比如只需执行两次
		for i := 0; i < 2; i++ {
			intChan <- i
			time.Sleep(time.Second)
		}
		// 关闭这个管道
		close(intChan)
	}()

	for {
		if timer == nil {
			timer = time.NewTimer(t)
		} else {
			// 通过 timer.Reset 函数重置这个定时器，达到目的
			// 将超时时间重置
			timer.Reset(t)
		}

		// 堵塞，谁有数据，就执行谁
		// 只会执行一次
		// 如果配合 for 死循环，可以达到一直监听管道的目的
		select {
		case e, ok := <-intChan:
			// 如果管道关闭，表示这个 intChan 管道不可用使用，那么这个 ok 就是 false
			if !ok {
				// 结束这个定时器
				return
			}
			fmt.Printf("定时器正在执行任务！时间：%v\t, 管道值：%v\n", time.Now().Format("2006-01-02 15:04:05"), e)
		case <-timer.C:
			// 如果 intChan 超过 3秒 没有数据，则会执行
			fmt.Printf("超时！\n")
		}
	}

}

// 定时器例子，达到 断续器 的效果，周而复始执行
func timer4() {
	t := time.Second * 3
	var timer *time.Timer

	for {
		if timer == nil {
			timer = time.NewTimer(t)
		} else {
			// 通过 timer.Reset 函数重置这个定时器，达到目的
			// 将超时时间重置
			timer.Reset(t)
		}

		// 堵塞，谁有数据，就执行谁
		// 只会执行一次
		// 如果配合 for 死循环，可以达到一直监听管道的目的
		select {
		case <-timer.C:
			fmt.Printf("执行任务，当前时间：%v\n", time.Now().Format("2006-01-02 15:04:05"))
		}
	}
}

// ======================  断续器

// 周而复始的执行
func timer5() {
	ticker := time.NewTicker(time.Second * 3)
	for {
		select {
		case <-ticker.C:
			fmt.Printf("执行任务，当前时间：%v\n", time.Now().Format("2006-01-02 15:04:05"))
		}
	}
	// ticker.Stop() 停止断续器
}

func main() {
	go timer4()

	// 主线程 睡眠 10 秒
	time.Sleep(time.Second * 10)

}
